// Copyright (C) ZHENG Zhong <heavyzheng nospam-at gmail D0T com>
//
// $Id: destination.hpp 216 2008-09-03 08:13:29Z heavyzheng $
//

#ifndef ZZHENG_LOGGING_DESTINATION_HPP_20080901__
#define ZZHENG_LOGGING_DESTINATION_HPP_20080901__

#include <zzheng/logging/config.hpp>
#include <boost/any.hpp>
#include <cassert>
#include <typeinfo>
#include <string>
#include <map>

namespace zzheng {
namespace logging {

    //! The destination type enumerations.
    enum destination_type {
        null_dev_destination = 0,
        console_destination,
        single_file_destination,
        rolling_file_destination,
    }; // enum destination_type

    ////////////////////////////////////////////////////////////////////////////////////////////////

    //! The logging destination configuration.
    class destination {

    public:

        typedef std::map<std::string, boost::any> prop_map; //!< The property map.

    public:

        //! Default constructor. Constructs a null_dev destination.
        explicit destination(): type_(null_dev_destination), props_() {
            // Do nothing.
        }

        //! Constructs a destination of the specified type.
        //! \param type  the destination type.
        explicit destination(destination_type type): type_(type), props_() {
            // Do nothing.
        }

        // Use auto-generated copy constructor.
        // Use auto-generated copy assignment.
        // Use auto-generated destructor.

        //! Returns the destination type.
        //! \return the destination type.
        destination_type type() const {
            return type_;
        }

        void copy_props(const destination& source) {
            props_ = source.props_;
        }

        //! Checks if the typed property of the specified name exists.
        //! \tparam T     the property value type.
        //! \param  name  the property name.
        //! \return true if the typed property of the specified name exists, false otherwise.
        template<typename T>
        bool has_prop(const std::string& name) const {
            prop_map::const_iterator i = props_.find(name);
            return (i != props_.end() && i->second.type() == typeid(T));
        }

        //! Returns the typed property value by name.
        //! \pre has_prop<T>(name)
        //! \tparam T     the property value type.
        //! \param  name  the property name.
        //! \return the typed property value.
        template<typename T>
        T get_prop(const std::string& name) const {
            prop_map::const_iterator i = props_.find(name);
            assert(i != props_.end() && "Property should have existed.");
            if (i == props_.end()) {
                throw std::exception(); // TODO:
            } else {
                try {
                    return boost::any_cast<T>(i->second);
                } catch (const boost::bad_any_cast&) {
                    assert(! "Property should have had the proper type.");
                    throw std::exception(); // TODO:
                }
            }
        }

        //! Returns the typed property value by name. If the requested property does not exist, or
        //! if it is not of the requested type, the default value is returned.
        //! \tparam T     the property value type.
        //! \param  name  the property name.
        //! \param  def   the default value to return.
        //! \return the typed property value or the default value.
        template<typename T>
        T get_prop(const std::string& name, const T& def) const {
            if (has_prop<T>(name)) {
                return get_prop<T>(name);
            } else {
                return def;
            }
        }

        //! Sets a typed value to a property. If the property already contains a value, the
        //! original value will be overwritten.
        //! \tparam T      the property value type.
        //! \param  name   the property name.
        //! \param  value  the property value to set.
        template<typename T>
        void set_prop(const std::string& name, const T& value) {
            props_[name] = value;
        }

    private:

        destination_type type_;  //!< The destination type.
        prop_map         props_; //!< The properties.

    }; // class destination


} // namespace zzheng::logging
} // namespace zzheng

#endif // ZZHENG_LOGGING_DESTINATION_HPP_20080901__



